﻿
namespace Aeon.Emulator.Instructions.Arithmetic
{
    internal static class Add
    {
        [Opcode("00/r rmb,rb|02/r rb,rmb|04 al,ib|80/0 rmb,ib", OperandSize = 16 | 32, AddressSize = 16 | 32)]
        public static void ByteAdd(Processor p, ref byte dest, byte src)
        {
            int sResult = (sbyte)dest + (sbyte)src;
            uint uResult = (uint)dest + (uint)src;

            dest = (byte)uResult;

            p.ByteUpdateFlags(sResult, uResult, EFlags.Carry | EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }
        
        [Opcode("01/r rmw,rw|03/r rw,rmw|05 ax,iw|81/0 rmw,iw|83/0 rmw,ibx", AddressSize = 16 | 32)]
        public static void WordAdd(Processor p, ref ushort dest, ushort src)
        {
            int sResult = (short)dest + (short)src;
            uint uResult = (uint)dest + (uint)src;

            dest = (ushort)uResult;

            p.WordUpdateFlags(sResult, uResult, EFlags.Carry | EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }
        [Alternate("WordAdd", AddressSize = 16 | 32)]
        public static void DWordAdd(Processor p, ref uint dest, uint src)
        {
            long sResult = (long)(int)dest + (long)(int)src;
            ulong uResult = (ulong)dest + (ulong)src;

            dest = (uint)(uResult & 0xFFFFFFFF);

            p.DWordUpdateFlags(sResult, uResult, EFlags.Carry | EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }
    }

    internal static class Adc
    {
        [Opcode("10/r rmb,rb|12/r rb,rmb|14 al,ib|80/2 rmb,ib", OperandSize = 16 | 32, AddressSize = 16 | 32)]
        public static void ByteCarryAdd(Processor p, ref byte dest, byte src)
        {
            int sResult = (sbyte)dest + (sbyte)src;
            uint uResult = (uint)dest + (uint)src;

            uint c = (uint)(p.Flags & EFlags.Carry);
            sResult += (int)c;
            uResult += c;

            dest = (byte)(uResult & 0xFF);

            p.ByteUpdateFlags(sResult, uResult, EFlags.Carry | EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }

        [Opcode("11/r rmw,rw|13/r rw,rmw|15 ax,iw|81/2 rmw,iw|83/2 rmw,ibx", AddressSize = 16 | 32)]
        public static void WordCarryAdd(Processor p, ref ushort dest, ushort src)
        {
            int sResult = (short)dest + (short)src;
            uint uResult = (uint)dest + (uint)src;

            uint c = (uint)(p.Flags & EFlags.Carry);
            sResult += (int)c;
            uResult += c;

            dest = (ushort)uResult;

            p.WordUpdateFlags(sResult, uResult, EFlags.Carry | EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }
        [Alternate("WordCarryAdd", AddressSize = 16 | 32)]
        public static void DWordCarryAdd(Processor p, ref uint dest, uint src)
        {
            long sResult = (long)(int)dest + (long)(int)src;
            ulong uResult = (ulong)dest + (ulong)src;

            uint c = (uint)(p.Flags & EFlags.Carry);
            sResult += c;
            uResult += c;

            dest = (uint)(uResult & 0xFFFFFFFFu);

            p.DWordUpdateFlags(sResult, uResult, EFlags.Carry | EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }
    }

    internal static class Inc
    {
        [Opcode("FE/0 rmb", OperandSize = 16 | 32, AddressSize = 16 | 32)]
        public static void ByteIncrement(Processor p, ref byte dest)
        {
            int sResult = (sbyte)dest + (sbyte)1;
            uint uResult = (uint)dest + (uint)1;

            dest = (byte)(uResult & 0xFF);

            p.ByteUpdateFlags(sResult, uResult, EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }

        [Opcode("40+ rw|FF/0 rmw", AddressSize = 16 | 32)]
        public static void WordIncrement(Processor p, ref ushort dest)
        {
            int sResult = (short)dest + (short)1;
            uint uResult = (uint)dest + (uint)1;

            dest = (ushort)(uResult & 0xFFFF);

            p.WordUpdateFlags(sResult, uResult, EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }
        [Alternate("WordIncrement", AddressSize = 16 | 32)]
        public static void DWordIncrement(Processor p, ref uint dest)
        {
            long sResult = ((long)(int)dest) + 1L;
            ulong uResult = (ulong)dest + 1UL;

            dest = (uint)(uResult & 0xFFFFFFFF);

            p.DWordUpdateFlags(sResult, uResult, EFlags.Overflow | EFlags.Sign | EFlags.Zero | EFlags.Parity);
        }
    }
}
